之前的 memoize 快取函數是簡單閉包(Closure)的應用方式, 你可以試試動手做, 幫 memoize 函數加上快取過期時間, 或者觸發回應快取內容變更事件, 甚至增加建立快取使用不同的儲存媒體方式儲存.
Typescript 的裝飾器Decorators 就像C# 的Attribute , 它可以實現AOP 面向切面編程開發, 不修改原來的程式碼的前提下, 給原來的程式碼增加額外的功能.
想要用Typescript 裝飾器, 必須修改tsconfig.json 參數如下
{
"compilerOptions": {
"target": "es5",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
首先Typescript 建立裝飾器的方式必須是回傳函數, 以下是方法裝飾器的典型範例
function CustomDecorator() {
return (target: object, methodName: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor => {
...
return descriptor;
};
}
方法裝飾器函數提供三個參數
首先我們來建立快取(Cache) 裝飾器, 以下示範我們是如何實作的
function CacheDecorator() {
return (target: object, methodName: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor => {
if (!descriptor.hasOwnProperty('set') && descriptor.value) {
descriptor.value = createCacheDecorator(target, descriptor.value);
} else {
throw new Error(`Can't set cache decorator on a non-method`);
}
return descriptor;
};
}
首先CacheDecorator 裡面檢查成員名稱是否為非 'set' 開頭, 並且是否有提供 method 資訊
if (!descriptor.hasOwnProperty('set') && descriptor.value) {
...
}
如果是的話, 就建立新的方法取代原本物件的方法定義
descriptor.value = createCacheDecorator(target, descriptor.value);
如同之前的 memoize 函數, 同樣地我們建立 CacheDecorator 閉包函數
function createCacheDecorator(target: object, method: (...args) => any): () => any {
const cache: {} = {};
return function(...args: any[]): any {
const argsKey: string = JSON.stringify(args);
if( !cache.hasOwnProperty(argsKey) ){
const res = method.call(this, ...args);
cache[argsKey] = res;
return res;
}
return cache[argsKey];
};
}
然後我們用新的 CacheDecorator 閉包函數取代物件中原本的方法.
descriptor.value = createCacheDecorator(target, descriptor.value);
假設你企圖在物件裡, 用我們實作的 CacheDecorator 裝飾器類別, 掛載在屬性上
class SomeClass {
@CacheDecorator()
id: number = 1;
}
Typescript 將會顯示以下錯誤訊息
Unable to resolve signature of property decorator when called as an expression.
現在我們可以在任何物件中的任何方法, 掛載這個 CacheDecorator 裝飾器
class User {
@CacheDecorator()
add(a: number, b: number): number {
return a + b;
}
}
這是多麼酷炫的應用, 可以讓我們不改變已現有的程式碼內容, 再加上具有快取(Cache) 的功能.
Typescript 的物件類別只能單一繼承, 因此你不能這樣做
class Plyaer extends Human, Animal {
...
}
Typescript 會告知你, 物件不能夠多重繼承
Classes can only extend a single class.
但我們可以利用另一種方式來建構它們, 這種方式稱為混合(Mixins).
首先必須建立建構元類型
type Constructor<T = {}> = new (...args: any[]) => T;
然後我們提供一個為某個物件類型增加 address 屬性的方法
function AddAddress<TBase extends Constructor>(base: TBase) {
return class extends base {
address: string = "";
}
}
AddAddress 方法會另外產生新的物件類型並繼承 base, 再回傳這個新的物件類型.
於是我們就可以這樣使用... 幫 User 類型增加 address 屬性
class User {
name: string = "flash";
}
const AddressUser = AddAddresses(User);
let obj = new AddressUser();
console.log(obj.address);
同樣地我們也能為物件類別增加方法
function AddSayHello<TBase extends Constructor>(base: TBase) {
return class extends base {
sayHello(msg: string): void {
console.log("hello " + msg);
}
}
}
const UserCanSayHello = AddSayHello(User);
let obj = new UserCanSayHello();
console.log(obj.sayHello());
因為想學TYPESCRIPT Decoraotr,想問一問tsconfig.json 應該儲存在那裏? 是不是儲存在"C:\Program Files\nodejs\node_modules\npm"裏面? THX
應該要放在你的專案根目錄底下